package haxe.util;

import haxe.util.Compare;
import haxe.util.Collection;

//Abstract
class SortedCollection<T> implements Collection<T>//extends AbstractCollection<T>
{
	public var comparator(default,null):Comparator<T>;
	public var naturalOrder(default,null):Bool;
	public var size(getSize,null):Int;
	private var _compReady:Bool;
	
	private function new( c:Comparator<T> )
	{
		comparator = c;
		comp = compComp;
		eq = compEq;
		
		naturalOrder = 
			if( c == null )
			{
				_compReady = false;
				true;
			}
			else
			{
				_compReady = true;
				false;
			}
	}
	
	public function add(o:T):Void
	{
		if ( ! _compReady )
		{
			comparator = Comparators.getComparator( o );
			_compReady = true;
		}
	}
	
	public function toString():String
	{
		return "SortedCollection";
	}
	
	//virtual functions
	private function eq( o1:T, o2:T ):Bool{return false;}
	private function comp( o1:T, o2:T ):Int{return 0;}
	
	private function compComp( o1:T, o2:T ):Int
	{
		return comparator.compare( o1, o2 );
	}
	
	private function compEq( o1:T, o2:T ):Bool
	{
		return comparator.equals( o1, o2 );
	}
	
	private function natComp( o1:Comparable<T>, o2:T ):Int
	{
		return o1.compareTo( o2 );
	}
	
	private function natEq( o1:Comparable<T>, o2:T ):Bool
	{
		return o1.compareTo( o2 ) == 0;
	}
	
	public function containsAll(c:Collection<T>, ?equals: T->T->Bool ):Bool
	{
		for ( i in c )
			if ( ! this.contains( i,equals ) ) return false;
		return true;
	}
	
	public function removeAll(c:Collection<T>, ?equals: T->T->Bool):Bool
	{
		var r:Bool = false;
		for ( i in c )
		{
			if ( remove(i, equals) && ! r ) r = true;
		}
		return r;
	}
	
	public function addAll(c:Collection<T>):Void
	{
		for ( i in c )
			add(i);
	}
	
	public function toArray():Array<T>
	{
		return Lambda.array( this );
	}
	
	//"Abstract" methods
	public function contains(o:T, ?equals: T->T->Bool ):Bool{return false;}
	public function remove(o:T, ?equals: T->T->Bool):Bool{return false;}
	public function isEmpty():Bool{return true;}
	public function clear():Void{}
	public function iterator():Iterator<T>{return null;}
	
	private function getSize():Int{return 0;}
}